/**
 * 
 */
package IC.Analyzer;

import IC.AST.PropogatingVisitor;
import IC.AST.nodes.*;
import IC.Analyzer.Types.*;

/**
 * Checks general program structure:
 * 1. check that a main method is defined
 * 2. break and continue only used in loop
 * 
 */
public class StructureChecker extends Checker<Object,Object>
implements PropogatingVisitor<Object,Object> {

	int loopCount = 0;
	private Program root;

	/**
	 * rule 1
	 */
	public StructureChecker(Program root) throws Exception {
		loopCount = 0;
		this.root = root;
		root.accept(this, null);
		if(root.getMain() == null)	
			error(root,"`main' could not be found");
	}

	/**
	 * rule 2
	 */
	public Type visit(WhileStmt that, Object d) throws Exception {
		// check statements
		that.getCondition().accept(this,d);
		loopCount++;
		that.getBody().accept(this,d);
		loopCount--;
		return null;
	}

	/**
	 * rule 2
	 */
	public Type visit(BreakStmt that, Object d) throws Exception {
		if(loopCount <= 0) {
			error(that,"`break' cannot be used outside of a loop");
		}
		return null;
	}

	/** 
	 * rule 2
	 */
	public Type visit(ContinueStmt that, Object d) throws Exception {
		if (loopCount <= 0) {
			error(that,"`continue' cannot be used outside of a loop");
		}
		return null;
	}

	/**
	 * rule 1
	 */
	public Type visit(MethodDecl that, Object d) throws Exception {
		if (that.getReturnType() == null && 
				that.getFormals().size() == 1 && 
				that.getFormals().get(0).getType().getType() == ArrayType.getIt(StringType.getIt()) &&
				that.isStatic()) 
		{
			if(root.getMain() != null)
				error(that, "redefinition of `main' method");
			root.setMain(that);
		}

		if(that.getReturnType() != null) {
			that.getReturnType().accept(this,d);
		}
		for(FormalDecl fd : that.getFormals()) {
			fd.accept(this,d);
		}
		if(that.getBody() != null) {
			that.getBody().accept(this,d);
		}
		return null;
	}



}
